package com.ls.shiroWithJwt.config;

import com.ls.shiroWithJwt.shiro.AuthRealm;
import com.ls.shiroWithJwt.shiro.cache.ShiroSessionDao;
import com.ls.shiroWithJwt.shiro.filter.JwtFilter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Configuration
//@ConfigurationProperties(prefix="shiroFilter")
public class ShiroConfig {

    private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());

    @ConfigurationProperties(prefix="shiroFilter")
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        //SecurityManager manager= securityManager(authRealm);
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JwtFilter());
        bean.setFilters(filterMap);


        //配置登录的url和登录成功的url
        bean.setLoginUrl("/login");
        bean.setSuccessUrl("/index");
        return bean;
    }


    //配置核心安全事务管理器
    @Bean
    public SecurityManager securityManager(@Qualifier("authRealm")AuthRealm authRealm, @Qualifier("shiroRedisCacheManager")CacheManager cacheManager,
                                           @Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher,
                                           @Qualifier("shiroSessionManager")SessionManager shiroSessionManager) {

        logger.info("--------------shiro已经加载----------------");
        DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
        authRealm.setCredentialsMatcher(matcher);
        // 设置realm.
        manager.setRealm(authRealm);

        //注入缓存管理器;
        //注意:开发时请先关闭，如不关闭热启动会报错
        manager.setCacheManager(cacheManager);//这个如果执行多次，也是同样的一个对象;

        manager.setSessionManager(shiroSessionManager);
        //注入记住我管理器;
//        manager.setRememberMeManager(rememberMeManager());


        return manager;
    }


    @Bean
    public SessionManager shiroSessionManager( @Qualifier("redisJdkTemplate")RedisTemplate<String,Object> redisClient,
                                               @Value("${shiro.expireMinute:60}")Integer expireMinute){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(expireMinute*60*1000);
        sessionManager.setSessionDAO(new ShiroSessionDao(redisClient,expireMinute, TimeUnit.MINUTES));
        return sessionManager;
    }


    /**
     * cookie对象;
     * @return
     * */
//    @Bean
    public SimpleCookie rememberMeCookie(){
        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        /* simpleCookie.setMaxAge(259200);*/
        simpleCookie.setMaxAge(20);
        logger.info("--------------rememberMeCookie init---------------"+simpleCookie);
        return simpleCookie;
    }
    /**
     * cookie管理对象;
     * @return
     */
//    @Bean
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());

        logger.info("--------------rememberMeManager init---------------"+cookieRememberMeManager);
        return cookieRememberMeManager;
    }


    /**
     * 保证实现了Shiro内部lifecycle函数的bean执行
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }

    /**
     * AOP式方法级权限检查
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        //  SecurityManager manager= securityManager(authRealm);
        AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //指定加密方式为MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //加密次数
        credentialsMatcher.setHashIterations(1);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher;
    }

//    public static void main(String args[]){
//        SimpleHash simpleHash = new SimpleHash("MD5", "123456", null, 1);
//        System.out.println(simpleHash.toString());
//    }

}
